﻿using System;
using System.Collections.Generic;
using System.Text;
using BlueLotus7.Contract;
using BlueLotus7.Common;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Xml;

namespace BlueLotus7.Contract
{
    [DataContract]
    public class Audit : IValidate
    {
        [DataMember]
        protected Guid auditKey;
        [DataMember]
        protected AuditType auditType;
        [DataMember]
        protected DateTime createdStamp;
        [DataMember]
        protected string sourceKey;
        [DataMember]
        protected string sourceName;
        [DataMember]
        protected List<AuditItem> auditItems = new List<AuditItem>();
        [DataMember]
        protected List<Audit> childAudits = new List<Audit>();

        #region Property

        /// <summary>
        /// The owner key.
        /// </summary>
        public Guid AuditKey
        {
            get { return auditKey; }
        }

        /// <summary>
        /// The content.
        /// </summary>
        public AuditType AuditType
        {
            get { return auditType; }
        }

        /// <summary>
        /// The created stamp.
        /// </summary>
        public DateTime CreatedStamp
        {
            get { return createdStamp; }
        }

        /// <summary>
        /// The source key.
        /// </summary>
        public string SourceKey
        {
            get { return sourceKey; }
        }

        /// <summary>
        /// The source name.
        /// </summary>
        public string SourceName
        {
            get { return sourceName; }
        }

        /// <summary>
        /// Audit items.
        /// </summary>
        public List<AuditItem> AuditItems
        {
            get { return auditItems; }
        }

        /// <summary>
        /// Child Audits
        /// </summary>
        public List<Audit> ChildAudits
        {
            get { return childAudits; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="auditType">The audit type.</param>
        /// <param name="sourceKey">The source key. (Integer, guid or other any identity)</param>
        /// <param name="sourceName">The source name.</param>
        public Audit(AuditType auditType, string sourceKey, string sourceName)
        {
            this.auditKey = Guid.NewGuid();
            this.auditType = auditType;
            this.sourceKey = sourceKey;
            this.sourceName = sourceName;
            this.createdStamp = DateTime.Now;
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="auditKey">The audit key.</param>
        /// <param name="auditType">The audit type.</param>
        /// <param name="sourceKey">The source key. (Integer, guid or other any identity)</param>
        /// <param name="sourceName">The source name.</param>
        /// <param name="createdStamp">The created stamp.</param>
        public Audit(Guid auditKey, AuditType auditType, string sourceKey, string sourceName, DateTime createdStamp)
        {
            this.auditKey = auditKey;
            this.auditType = auditType;
            this.sourceKey = sourceKey;
            this.sourceName = sourceName;
            this.createdStamp = createdStamp;
        }

        #endregion

        public XmlNode ToXml()
        {
            XmlDocument xmlDocument = new XmlDocument();
            XmlDocumentFragment docFrag = xmlDocument.CreateDocumentFragment();
            StringBuilder sb = new StringBuilder();
            sb.Append("<Audit type=\"" + auditType.ToString() + "\" stamp=\"" + createdStamp.Year + "-" + createdStamp.Month + "-" + createdStamp.Day + " " + createdStamp.Hour + ":" + createdStamp.Minute + ":" + createdStamp.Second + ":" + createdStamp.Millisecond + "\">");
            sb.Append("<SourceKey>" + sourceKey + "</SourceKey>");
            sb.Append("<SourceName>" + sourceName + "</SourceName>");
            StringBuilder fields = new StringBuilder();
            if (auditItems != null)
            {
                foreach (AuditItem auditItem in auditItems)
                {
                    fields.Append(auditItem.ToXml().OuterXml);
                }
            }
            sb.Append("<Fields>" + fields.ToString() + "</Fields>");
            StringBuilder children = new StringBuilder();
            if (childAudits != null)
            {
                foreach (Audit item in childAudits)
                {
                    fields.Append(item.ToXml().OuterXml);
                }
            }
            sb.Append("<Childrens>" + children.ToString() + "</Childrens>");
            sb.Append("</Audit>");
            docFrag.InnerXml = sb.ToString();
            xmlDocument.DocumentElement.AppendChild(docFrag);
            return xmlDocument.ChildNodes[0];
        }

        #region IValidate 成员

        public bool IsValid
        {
            get
            {
                try
                {
                    Validate();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        public void Validate()
        {
            if (auditType != AuditType.Add && string.IsNullOrWhiteSpace(sourceKey))
            {
                throw new InvalidObjectException("sourceKey");
            }
            else if (string.IsNullOrWhiteSpace(sourceName))
            {
                throw new NullOrEmptyStringException("sourceName");
            }
            else
            {
                foreach (var one in this.auditItems)
                {
                    one.Validate();
                }

                foreach (var one in childAudits)
                {
                    one.Validate();
                }
            }
        }

        #endregion
    }
}
